
package com.yadong.smarthome2.connections;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;

import com.yadong.smarthome2.device.Device;
import com.yadong.smarthome2.devicefinder.BluetoothDeviceFinder;
import com.yadong.smarthome2.messageparser.RequestManager;
import com.yadong.smarthome2.protocol2.ALog;
import com.yadong.smarthome2.protocol2.Protocol;
import com.yadong.smarthome2.protocol2.RequestProtocol.Request;
import com.yadong.smarthome2.protocol2.ResultProtocol.DeviceInfo;
import com.yadong.smarthome2.protocol2.ResultProtocol.DeviceInfo.Status;
import com.yadong.smarthome2.protocol2.ResultProtocol.Function;
import com.yadong.smarthome2.protocol2.ResultProtocol.Result;
import com.yadong.smarthome2.utils.Utils;

public class BluetoothConnection extends Connection {
    private BluetoothSocket mBluetoothSocket;
    private InputStream mInputStream;
    private OutputStream mOutputStream;

    public BluetoothConnection(Device device, ConnectionListener listener,
            MessageSendThread sendThread, RequestManager requestManager,
            ResultListener resultListener) {
        super(device, listener, sendThread, requestManager, resultListener);
    }

    @Override
    protected boolean connectDevice(Device device) {
        BluetoothDevice bluetoothDevice =
                BluetoothDeviceFinder.BLUETOOT_DEVICES.get(device);
        try {
            mBluetoothSocket = bluetoothDevice
                    .createRfcommSocketToServiceRecord(Protocol.BLUETOOTH_UUID);
            mBluetoothSocket.connect();
            mInputStream = mBluetoothSocket.getInputStream();
            mOutputStream = mBluetoothSocket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        if (mInputStream == null || mOutputStream == null) {
            return false;
        }
        return true;
    }

    @Override
    protected void forceStopConnection() {
        Utils.safeClose(mInputStream);
        Utils.safeClose(mOutputStream);
        Utils.safeClose(mBluetoothSocket);
    }

    @Override
    protected void queyDeviceFunctions() {
        Request.Builder builder = Request.newBuilder();
        builder.setTime(System.currentTimeMillis());
        builder.setTag(Protocol.REQUEST_FOR_DEVICE_INFO);
        sendData(builder.build());
    }

    private boolean parseDeviceInfo(Result result) {
        if (result == null ||
                !Protocol.REQUEST_FOR_DEVICE_INFO.equals(result.getTag())) {
            return false;
        }
        DeviceInfo deviceInfo = result.getDeviceInfo();
        List<Function> functions = deviceInfo.getFunctionsList();
        List<Status> status = deviceInfo.getStatusList();
        initDevice(deviceInfo.getType(), deviceInfo.getVersion(), functions, status);
        return true;
    }

    @Override
    protected Result doLoop() throws Exception {
        Result result = Result.parseDelimitedFrom(mInputStream);
        ALog.logd(this, "get result ... " + result);
        parseDeviceInfo(result);
        return result;
    }

    @Override
    protected boolean sendDataInternal(final Request request) {
        if (mOutputStream == null) {
            return false;
        }
        doSend(new Runnable() {
            @Override
            public void run() {
                try {
                    //send urgent package to ensure connection
                    request.writeDelimitedTo(mOutputStream);
                    mOutputStream.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                    // if error to send data.. force stop connection
                    forceStop();
                }
            }
        });
        return true;
    }

}
